
package xml;

import java.util.Collection;
import java.util.Hashtable;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import data.AdminTuple;
import data.MovieTuple;
import data.RatingTuple;
import data.SystemData;
import data.UserTuple;

/**
 * contains functions to read an XML file with DOM
 *
 * @author The secret 4 and the dog
 *
 */

public class DataManipulate {

    /** Creates a new instance of DataManipulate
     *
     */
    public DataManipulate() {
    }
    /**
     * retrives the users from the XML file and returns them in a TreeSet
     * @param document the document to retrive the data from
     * @return a TreeSet of all the users in the database
     */
    private static Hashtable<String,UserTuple> getUsers(Document document){
    	Hashtable<String,UserTuple> users = new Hashtable<String,UserTuple>(); 	//creates a new container for the users
        NodeList userList = document.getElementsByTagName("Users").item(0).getChildNodes(); //retrives the user list from the XML document
        for(int i=0 ; i<userList.getLength() ; i++) { 			//adds all the users to the container
            Node node = userList.item(i);
            if (userList.item(i).getNodeType()!=Node.TEXT_NODE) {
	            NamedNodeMap userAttr =  node.getAttributes();
	            String uName = userAttr.getNamedItem("name").getNodeValue();
	            String uPw = userAttr.getNamedItem("password").getNodeValue();
	            String uSex = userAttr.getNamedItem("sex").getNodeValue();
	            String uBdate = userAttr.getNamedItem("bdate").getNodeValue();
	            String uType = userAttr.getNamedItem("type").getNodeValue();
	            UserTuple userTuple;
	            if (uType.equals("admin")){
	            	userTuple = new AdminTuple(uName, uPw, uSex,uBdate, uType, false);
	            }else{
	            	userTuple =  new UserTuple(uName, uPw, uSex,uBdate, uType);
	            }
	            users.put(userTuple.getKey(),userTuple);
            }
         }
        return users;
    }

    /**
     * retrives the movies from the XML file and returns them in a HashTable,
     * the key is movie_name%movie_year assuming no two movies with the same
     * name and year exists
     * @param document the document to retrive the data from
     * @return a TreeSet with all the movies
     */
    private static Hashtable<String,MovieTuple> getMovies(Document document){
        Hashtable<String,MovieTuple> movies = new Hashtable<String,MovieTuple>();  	//creates a new container for the movies
        NodeList movieList = document.getElementsByTagName("Movies").item(0).getChildNodes(); //retrives the movie list from the XML document
        for(int i=0 ; i<movieList.getLength() ; i++) {				//adds all the movies to the container
            Node node = movieList.item(i);
            if (node.getNodeType()!=Node.TEXT_NODE) {
	            NamedNodeMap movieAttr =  node.getAttributes();
	            String mName = movieAttr.getNamedItem("name").getNodeValue();
	            String mCategory = movieAttr.getNamedItem("category").getNodeValue();
	            String mDirector = movieAttr.getNamedItem("director").getNodeValue();
	            String mYear = movieAttr.getNamedItem("year").getNodeValue();
	            String mRating = movieAttr.getNamedItem("rating").getNodeValue();
	            String mRaters = movieAttr.getNamedItem("raters").getNodeValue();
	            String mLength = movieAttr.getNamedItem("length").getNodeValue();
	            String mLang = movieAttr.getNamedItem("language").getNodeValue();
	            String mPic = movieAttr.getNamedItem("picture").getNodeValue();
	            MovieTuple movieTuple= new MovieTuple(mName,mCategory,mDirector,mLang,mRaters,mRating,mYear,mLength,mPic);

	            movies.put(movieTuple.getKey(),movieTuple);
            }
         }
        return movies;
    }


    /*/**
     * retrives the recommendations from the XML file and returns them in a TreeSet
     * @param document the document to retrive the data from
     * @return a TreeSet with all the recommendations

    private static Hashtable<String, RatingTuple> getRating(Document document){
    	Hashtable<String, RatingTuple> recs = new  Hashtable<String, RatingTuple>();		//creates a container for the recommendations
        NodeList recList = document.getElementsByTagName("Reccomendations").item(0).getChildNodes(); //retrives the recommendations from the XMl document
        for(int i=0 ; i<recList.getLength() ; i++) {			//adds all the recommendations to the container
            Node node = recList.item(i);
            if (node.getNodeType()!=Node.TEXT_NODE) {
	            NamedNodeMap recAttr =  node.getAttributes();
	            String rMovie = recAttr.getNamedItem("movie").getNodeValue();
	            String rUser = recAttr.getNamedItem("user").getNodeValue();
	            String rDate = recAttr.getNamedItem("date").getNodeValue();
	            String rRating = recAttr.getNamedItem("rating").getNodeValue();
	            String rDescription = recAttr.getNamedItem("description").getNodeValue();
	            RatingTuple ratingTuple=RatingTuple.createNew(rMovie, rUser, rDate, rRating, rDescription);
	            recs.put(ratingTuple.getKey(),ratingTuple);
            }
         }
        return recs;
    }*/

    
    public static void writeToFile(Collection<UserTuple> users ,Collection<MovieTuple> movies, Collection<RatingTuple> recommendations){
    	writeToFileWithName(users, movies, recommendations, "movies_db.xml");
    }
    
    /**
     * writes the given users ,movies and recommendations to the XML file.
     * @param users the users to be written to the XML file
     * @param movies the movies to be written to the XML file
     * @param recommendations the recommendations to be written to the XML document
     */
    public static void writeToFileWithName(Collection<UserTuple> users ,Collection<MovieTuple> movies, Collection<RatingTuple> recommendations, String filename){
    	Document document = XMLUtilityManagment.makeNewXML(".\\"+filename);  	//XML file to write to

    	Node userGroup = document.getElementsByTagName("Users").item(0);  			//user list
    	Node movieGroup = document.getElementsByTagName("Movies").item(0);			//movie list
    	Node recGroup = document.getElementsByTagName("Reccomendations").item(0);				//recommendation list

    	//adds all the users to the user list
    	for (UserTuple user : users){
    		userGroup.appendChild(addUser(user , document));
    	}
    	//adds all the movies to the movie list
    	for (MovieTuple movie : movies){
    		movieGroup.appendChild(addMovie(movie, document));
    	}
    	//adds all the recommendation to the recommendation list
    	for (RatingTuple rec : recommendations){
    		Element element = addRating(rec, document);
    		recGroup.appendChild(element);
    	}

    	//writes to the file
    	XMLUtilityManagment.writeXMLFile(document, ".\\movies_db.xml");
    }

    /**
     * given a user tuple - converts it to an XML document Element and adds it to the given XML document
     * @param user the user tuple
     * @param document the XML document
     * @return the XML document Element
     */
    static public Element addUser(UserTuple user , Document document){

    	//creates the element in the XML document
        Element  newUser = document.createElement("user");

        //adds the user data to the created element
        newUser.setAttribute("name" , ""+ user.get_name() );
        newUser.setAttribute("password", user.get_password());
        newUser.setAttribute("bdate", user.get_bdate());
        newUser.setAttribute("sex", ""+user.is_sex());
        newUser.setAttribute("type", user.get_type());
    	/*newUser.appendChild(newUser);
    	newUser = document.createElement("Users");*/

        return newUser;
    }

    /**
     * given a movie tuple - converts it to an 'XML document Element' and adds it to the given XML document
     * @param movie the movie tuple
     * @param document the XML document
     * @return the XML document Element
     */
    public static Element addMovie(MovieTuple movie, Document document){

    	//creates the element in the XML document
    	Element  newMovie = document.createElement("movie");

        //adds the movie data to the created element
    	newMovie.setAttribute("name" , ""+ movie.get_name() );
    	newMovie.setAttribute("category", movie.get_category());
    	newMovie.setAttribute("director", movie.get_director());
    	newMovie.setAttribute("year", ""+movie.get_year());
    	newMovie.setAttribute("raters", ""+movie.get_raters());
    	newMovie.setAttribute("rating", ""+movie.get_rating());
    	newMovie.setAttribute("length", ""+movie.get_length());
    	newMovie.setAttribute("language", movie.get_language());
    	newMovie.setAttribute("picture", ""+movie.get_picture());

    	return newMovie;
    }


    /**
     * given a recommendation tuple - converts it to an 'XML document Element' and adds it to the given XML document
     * @param recommendation the movie tuple
     * @param document the XML document
     * @return the XML document Element
     */
    public static Element addRating(RatingTuple rec, Document document){

    	//creates the element in the XML document
    	Element  newRec = document.createElement("recommendation");

    	//adds the recommendation to the recommendation list
        newRec.setAttribute("movie" , ""+ rec.get_movie().get_name() );
        newRec.setAttribute("user", ""+rec.get_user().get_name());
        newRec.setAttribute("date", rec.get_date());
        newRec.setAttribute("rating", ""+rec.get_rating());
        newRec.setAttribute("description", rec.get_description());
     //   System.out.println("newrec");
        if (newRec==null){
        	System.out.println("new rec is null");
        }
        return newRec;
    }

    /**
     * reads data from an XML file and returns the lists of movies , users and recommendations
     * @return the lists wrapped in SystemData
     */
    static public SystemData readFromFile(){
    	Document document = XMLUtilityManagment.readXMLFile(".\\movies_db.xml");
    	Hashtable<String, MovieTuple> movies = getMovies(document);
    	Hashtable<String, UserTuple> users = getUsers(document);

    	Hashtable<String, RatingTuple> rating = new  Hashtable<String, RatingTuple>();		//creates a container for the recommendations
        NodeList ratingList = document.getElementsByTagName("Reccomendations").item(0).getChildNodes(); //retrives the recommendations from the XMl document
        for(int i=0 ; i<ratingList.getLength() ; i++) {			//adds all the recommendations to the container
            Node node = ratingList.item(i);
            if (node.getNodeType()!=Node.TEXT_NODE) {
	            NamedNodeMap ratingAttr =  node.getAttributes();
	            String rMovie = ratingAttr.getNamedItem("movie").getNodeValue();
	            String rUser = ratingAttr.getNamedItem("user").getNodeValue();
	            String rDate = ratingAttr.getNamedItem("date").getNodeValue();
	            String rRating = ratingAttr.getNamedItem("rating").getNodeValue();
	            String rDescription = ratingAttr.getNamedItem("description").getNodeValue();
	            RatingTuple ratingTuple = RatingTuple.createNew(movies.get(rMovie) , users.get(rUser), rDate, rRating, rDescription);
	            rating.put(ratingTuple.getKey(),ratingTuple);
            }
         }

    	try {
			return SystemData.XMLinit(movies, users, rating);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

    }

}


